package top.superflow.flow.config.parse

import org.apache.commons.lang3.builder.ToStringBuilder
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.stereotype.Component
import top.superflow.exception.{InitException, RequestUnsupportedException}
import top.superflow.flow.config.{Config, Identifiable}
import top.superflow.flow.load.GlobalFlowConfiguration
import top.superflow.flow.runtime.cache.FlowRunTimeCache
import top.superflow.flow.runtime.context.GlobalContext
import top.superflow.lang.CollectionUtils
import top.superflow.log.Loggable


@Component
@Autowired
class ParserManager (globalContext: GlobalContext) extends Loggable{

  if(globalContext == null){
    throw new InitException("Failed to init ParserManager as globalContext is null.")
  }else{
    FlowConfigParserFactory.init(globalContext)
  }


  private var extFlowCache : FlowRunTimeCache = _

  def parse(flowConfiguration : GlobalFlowConfiguration) : FlowRunTimeCache= {
    if(flowConfiguration == null){
      throw new RequestUnsupportedException("The flow configuration could not be null!")
    }

    //need to keep parsing in below order
    parseIntoCache(flowConfiguration.getResources)

    parseIntoCache(flowConfiguration.getProcessProviders)

    parseIntoCache(flowConfiguration.getMappers)

    parseIntoCache(flowConfiguration.getProcesses)

    parseIntoCache(flowConfiguration.getFlows)


    extFlowCache = FlowRunTimeCache.getInstance

    extFlowCache
  }

  private def parseIntoCache[T <: Config, E <: Identifiable](configs : Map[String, Map[String, T]]) : Unit = {
    if(CollectionUtils.isEmpty(configs)){
      return
    }


    for ((groupKey, flows) <- configs) {
      for ((key, config) <- flows) {
        val parser = FlowConfigParserFactory.getInstance.getParser(config)
        if(parser == null){
          throw new RequestUnsupportedException("There is no corresponding parser for config [" + ToStringBuilder.reflectionToString(config) + "]")
        }
        val executable = parser.parse(config).asInstanceOf[E]
        FlowRunTimeCache.getInstance.cache[E](executable)
      }
    }
  }
}